package com.cxs.schedulecase.job;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @Project: schedule-case
 * @Author: cxs2014501@163.com
 * @Create: 2022/7/29 9:56
 * @Description:
 **/
@Slf4j
public abstract class BaseJob {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public void execute() {
        long startTime = System.currentTimeMillis();
        ScheduledJobEnum scheduledJob = getScheduledJobEnum();
        log.info("【定时任务:{}开始执行】 开始时间:【{}】", scheduledJob.getName(), new Date().toString());
        // 前置检查
        if (beforeExecute()){
            String lockKey = scheduledJob.getLockKey();
            String timeStamp = String.valueOf(System.currentTimeMillis());
            try {
                // 尝试获取锁资源
                Boolean lock = stringRedisTemplate.opsForValue().setIfAbsent(scheduledJob.getLockKey(), timeStamp, 10L, TimeUnit.SECONDS);
                // 加锁失败、不执行
                if (!lock) {
                    log.info("【定时任务{}】执行时间:【{}】,{}", scheduledJob.getName(), new Date(), "获取锁资源失败,不执行");
                    return;
                }
                doExecute();
                afterExecute();
            } catch (Exception e) {
                onException(e);
                e.printStackTrace();
            } finally {
                stringRedisTemplate.delete(lockKey);
                long endTime = System.currentTimeMillis();
                log.info("【定时任务:{}执行完成】 结束时间:【{}】【{}ms】", scheduledJob.getName(),
                        new Date(), endTime - startTime);
            }
        } else {
            log.info("【定时任务{}】{}", scheduledJob.getName(), "enable为false,不执行");
        }
    }

    public abstract ScheduledJobEnum getScheduledJobEnum();

    /**
     * 前置处理
     * @return
     */
    public abstract Boolean beforeExecute();

    /**
     * 具体执行方法
     */
    public abstract void doExecute();

    /**
     * 后置处理
     */
    public abstract void afterExecute();

    /**
     * 异理处理
     * @param e
     */
    public void onException(Exception e) {
        log.error("【定时任务{}执行失败】{}", this.getScheduledJobEnum().getName(), e);
    }
}
